package com.im.netty;

/**
 * @Author: szw
 * @Date: 2021/5/10 17:30
 */

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 考虑反射：
 * 　　由于在调用 SingletonHolder.instance 的时候，才会对单例进行初始化，而且通过反射，是不能从外部类获取内部类的属性的。
 * 　　所以这种形式，很好的避免了反射入侵。
 * 考虑多线程：
 * 　　由于静态内部类的特性，只有在其被第一次引用的时候才会被加载，所以可以保证其线程安全性。
 * 不需要传参的情况下 优先考虑静态内部类
 */
@Component
@Slf4j
public class NettyServer {
    @Value("${im.port}")
    private int port;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ServerBootstrap server;
    private ChannelFuture future;

    private static class SingletionWSServer {
        static final NettyServer instance = new NettyServer();
    }

    public static NettyServer getInstance() {
        return SingletionWSServer.instance;
    }

    public NettyServer() {
        // new 一个主线程组，用来接收进来的连接。
        bossGroup = new NioEventLoopGroup();
        // new 一个工作线程组，用来处理已经被接收的连接,一旦‘boss’接收到连接，就会把连接信息注册到‘worker’上
        workerGroup = new NioEventLoopGroup();
        // 一个启动NIO服务的辅助启动类,可以在这个服务中直接使用Channel
        server = new ServerBootstrap();

        // 如果没有设置group将会报java.lang.IllegalStateException: group not set异常
        server.group(bossGroup, workerGroup)
                // 设置NIO的双向通道
                .channel(NioServerSocketChannel.class)
                // 自定义初始化handler容器
                .childHandler(new NettyServerInitialzer());
    }

    public void start() {
        //自定义端口
        log.info("Netty服务启动--监听端口: {}", port);
        this.future = server.bind(port);
    }
}